<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="SSm1i" id="SSm1i"><span data-lake-id="u579c4213" id="u579c4213">典型回答</span></h1>
  <p data-lake-id="u800f7d7a" id="u800f7d7a"><br></p>
  <p data-lake-id="u65b7b0f1" id="u65b7b0f1"><span data-lake-id="ua2ffb860" id="ua2ffb860">所谓的IOC（inversion of control），就是控制反转的意思。何为控制反转？</span></p>
  <p data-lake-id="uf6b6f460" id="uf6b6f460"><span data-lake-id="u92bd369a" id="u92bd369a">​</span><br></p>
  <p data-lake-id="ub460fdf4" id="ub460fdf4"><span data-lake-id="ucf573d24" id="ucf573d24">在传统的程序设计中，应用程序代码通常控制着对象的创建和管理。例如，一个对象需要依赖其他对象，那么它会直接new出来对象。这样的设计通常被称为 "控制流程"。</span></p>
  <p data-lake-id="u2a0b7f46" id="u2a0b7f46"><span data-lake-id="u0831e6c1" id="u0831e6c1">​</span><br></p>
  <p data-lake-id="u76965382" id="u76965382"><span data-lake-id="uf517ce87" id="uf517ce87">而在IOC 中，控制关系发生了反转。控制权被转移到Spring容器中，容器负责创建和管理对象，并在需要的时候将它们注入到应用程序中。</span></p>
  <p data-lake-id="u49a0df45" id="u49a0df45"><span data-lake-id="u9505feeb" id="u9505feeb">​</span><br></p>
  <p data-lake-id="u40d25de9" id="u40d25de9"><strong><span data-lake-id="u22069d25" id="u22069d25">所以，原来这个对象的控制权在我们的代码中，我们自己new的对象，在Spring中，应用程序不再控制对象的创建，而是被动地接受由容器注入的对象。</span></strong></p>
  <p data-lake-id="ufefd98aa" id="ufefd98aa"><span data-lake-id="ua9bd2020" id="ua9bd2020">​</span><br></p>
  <p data-lake-id="uf5db48ed" id="uf5db48ed"><span data-lake-id="ub2d8429e" id="ub2d8429e">我们拿代码来举个例子：</span></p>
  <p data-lake-id="u48fb66d2" id="u48fb66d2"><span data-lake-id="u8756b410" id="u8756b410">​</span><br></p>
  <p data-lake-id="ua533ca3b" id="ua533ca3b"><span data-lake-id="u56446dc3" id="u56446dc3">下面是一个没有IOC的例子</span></p>
  <pre lang="java"><code>
class A {}
class B {

    // B需要将A的实例new出来，也就是我们说的控制
    private A a = new A();

    public void use() {
        System.out.print(a);
    }
        
}
</code></pre>
  <p data-lake-id="u40ff8213" id="u40ff8213"><span data-lake-id="u924c0bc6" id="u924c0bc6">​</span><br></p>
  <p data-lake-id="u9261570c" id="u9261570c"><span data-lake-id="u761e58b3" id="u761e58b3">当有了IOC之后</span></p>
  <pre lang="java"><code>
@Component // 说明A自己控制自己，把自己初始化出来，注入给了容器
class A {}

class B {

    // B不需要控制a，直接使用。如果A没有把自己注入给容器，B就不能使用
    @Resource
    private A a;

    public void use() {
        System.out.print(a);
    }
        
}
</code></pre>
  <p data-lake-id="ue08c201e" id="ue08c201e"><span data-lake-id="u560af5f7" id="u560af5f7">​</span><br></p>
  <p data-lake-id="u1d83fd79" id="u1d83fd79"><span data-lake-id="u062aa842" id="u062aa842">也就是说，</span><strong><span data-lake-id="u21c1045d" id="u21c1045d">没有Spring的话，我们要使用的对象，需要我们自己创建，而有了Spring的IOC之后，对象由IOC容器创建并管理，我们只需要在想要使用的时候从容器中获取就行了。</span></strong></p>
  <p data-lake-id="u4e9c8b17" id="u4e9c8b17"><span data-lake-id="u048c3c16" id="u048c3c16">​</span><br></p>
  <p data-lake-id="u22e9238d" id="u22e9238d"><span data-lake-id="ub12e5341" id="ub12e5341">值得说明的是，IOC只是一种思想和理念，可以有不同的实现方式。</span></p>
  <h2 data-lake-id="OsNr5" id="OsNr5"><span data-lake-id="u2f7dd6e6" id="u2f7dd6e6">IOC的优点</span></h2>
  <p data-lake-id="ubcfc09d7" id="ubcfc09d7"><br></p>
  <p data-lake-id="u3db9ccb6" id="u3db9ccb6"><span data-lake-id="u26160777" id="u26160777">使用IOC，有最少三个好处：</span></p>
  <p data-lake-id="uebb33df2" id="uebb33df2"><span data-lake-id="ucef06069" id="ucef06069">​</span><br></p>
  <ol list="uf37d0e7a">
   <li fid="u4f98e66f" data-lake-id="u05760f10" id="u05760f10"><strong><span data-lake-id="ub76ca0e2" id="ub76ca0e2">使用者不用关心引用bean的实现细节</span></strong><span data-lake-id="uc0802f36" id="uc0802f36">，譬如对于</span><code data-lake-id="ud7fc5925" id="ud7fc5925"><span data-lake-id="ue3da8572" id="ue3da8572">B b = new A(c,d,e,f);</span></code><span data-lake-id="uad155553" id="uad155553">来说，如果B要使用A，那还要把c，d，e，f多个类全都感知一遍，这显然是非常麻烦且不合理的</span></li>
  </ol>
  <p data-lake-id="uad00bf49" id="uad00bf49"><br></p>
  <ol list="uf37d0e7a" start="2">
   <li fid="u4f98e66f" data-lake-id="u9edff5a9" id="u9edff5a9"><strong><span data-lake-id="u2000d2b6" id="u2000d2b6">不用创建多个相同的bean导致浪费</span></strong><span data-lake-id="ub8ba8cd2" id="ub8ba8cd2">，仍然是：</span></li>
  </ol>
  <pre lang="java"><code>
A b = new A();
A z = new A();
</code></pre>
  <p data-lake-id="u8ddc3dcb" id="u8ddc3dcb"><span data-lake-id="u252dbdc9" id="u252dbdc9">如果B和Z都引用了A，那么B和Z就可能new 两个A实例，实际上，我们只需要一个就好了。</span></p>
  <p data-lake-id="u4601d982" id="u4601d982"><span data-lake-id="u328d5042" id="u328d5042">​</span><br></p>
  <ol list="u7e4159df" start="3">
   <li fid="u26da21e5" data-lake-id="uad26b50f" id="uad26b50f"><strong><span data-lake-id="u41f7ae9d" id="u41f7ae9d">Bean的修改使用方无需感知。</span></strong><span data-lake-id="u18ac34da" id="u18ac34da">同样是上面的例子，假如说BeanA需要修改，如果没有IOC的话，所有引用到A的其他bean都需要感知这个逻辑，并且做对应的修改。但是如果使用了IOC，其他bean就完全不用感知到</span></li>
  </ol>
  <h2 data-lake-id="Qbben" id="Qbben"><span data-lake-id="uf651ea20" id="uf651ea20">Spring的IOC</span></h2>
  <p data-lake-id="uc74e8fa7" id="uc74e8fa7"><span data-lake-id="u6ab824c7" id="u6ab824c7">对于Spring的IOC来说，它是IOC思想的一种实现方式。在容器启动的时候，它会根据每个bean的要求，将bean注入到SpringContainer中。如果有其他bean需要使用，就直接从容器中获取即可，如下图所示：</span></p>
  <p data-lake-id="ua696a17b" id="ua696a17b"><span data-lake-id="u50bdbb89" id="u50bdbb89">​</span><br></p>
  <p data-lake-id="u0abf959f" id="u0abf959f"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1673670476475-0a539106-38c7-4b14-a1eb-ec27d0888405.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_29%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <h1 data-lake-id="GdpVQ" id="GdpVQ"><span data-lake-id="ub5b091ee" id="ub5b091ee">扩展知识</span></h1>
  <h2 data-lake-id="W2JFP" id="W2JFP"><span data-lake-id="u2c7204c0" id="u2c7204c0">IOC是如何实现的？</span></h2>
  <p data-lake-id="ube708374" id="ube708374"><span data-lake-id="u34bf3dd5" id="u34bf3dd5">使用Spring的IOC容器能力，非常简单，如下代码所示：</span></p>
  <pre lang="java"><code>
ApplicationContext context= new AnnotationConfigApplicationContext("cn.wxxlamp.spring.ioc");
Bean bean = context.getBean(Bean.class);
bean.use();
</code></pre>
  <p data-lake-id="u5226bba0" id="u5226bba0"><span data-lake-id="u80e0cff7" id="u80e0cff7">从上面的代码中，我们也能看出来Spring的IOC是如何实现的：</span></p>
  <p data-lake-id="ued382d52" id="ued382d52"><span data-lake-id="u4d9f3d54" id="u4d9f3d54">​</span><br></p>
  <ol list="u2d66c74d">
   <li fid="u8e57f9d2" data-lake-id="u55672cf8" id="u55672cf8"><span data-lake-id="udf81c413" id="udf81c413">从配置元数据中获取要DI的业务POJO（这里的配置元数据包括xml，注解，configuration类等）</span></li>
   <li fid="u8e57f9d2" data-lake-id="ua22deb5f" id="ua22deb5f"><span data-lake-id="u615002ba" id="u615002ba">将业务POJO形成BeanDefinition注入到Spring Container中</span></li>
   <li fid="u8e57f9d2" data-lake-id="u841456c3" id="u841456c3"><span data-lake-id="u2221cf57" id="u2221cf57">使用方通过ApplicationContext从Spring Container直接获取即可。如下图所示：</span></li>
  </ol>
  <p data-lake-id="u7216cb31" id="u7216cb31"><br></p>
  <p data-lake-id="u8cafc7d7" id="u8cafc7d7"><img src="https://cdn.nlark.com/yuque/0/2023/png/719664/1673667342516-9f823f13-c1fe-41e2-85e1-f0764ed7cbbe.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_14%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ue8f6ff01" id="ue8f6ff01"><br></p>
  <p data-lake-id="u373859db" id="u373859db"><br></p>
 </body>
</html>